/*
 * -----------------------------------
 * Doubly linked list implementation
 * -----------------------------------
 * Copyright (C) 2021 AlexCr4ckPentest
 * -----------------------------------
*/



#pragma once

#ifndef __C_LINKED_LISTS__LIST_H
#define __C_LINKED_LISTS__LIST_H

#include <stddef.h>

struct list_node;
typedef void(*list_node_destructor_t)(struct list_node*);

struct list
{
    struct list_node* __head;
    struct list_node* __tail;
    size_t __size;
    list_node_destructor_t __node_destructor;
};

typedef struct list_node** list_iterator_t;
typedef list_iterator_t list_reverse_iterator_t;



/*
 * list_node interface
*/

struct list_node* list_node__construct(void* data, struct list_node* prev, struct list_node* next);



/*
 * list interface
*/

void list__construct(struct list* list);
void list__destruct(struct list* const list);
void list__copy(struct list* dst, struct list* const src);
void list__swap(struct list* lhs, struct list* rhs);
void list__remove_front(struct list* list);
void list__remove_back(struct list* list);
void list__clear(struct list* const list);
void list__add_front(struct list* list, void* data);
void list__add_back(struct list* list, void* data);
void list__merge_back(struct list* dst, struct list* const src);
void list__merge_front(struct list* dst, struct list* const src);
void list__remove_at(struct list* list, list_iterator_t pos);
void list__remove_after(struct list* list, list_iterator_t pos);
void list__remove_before(struct list* list, list_iterator_t pos);
void list__insert_at(struct list* list, void* data, list_iterator_t pos);
void list__insert_after(struct list* list, void* data, list_iterator_t pos);
void list__insert_before(struct list* list, void* data, list_iterator_t pos);
void list__merge_at(struct list* dst, struct list* const src, list_iterator_t pos);
void list__merge_after(struct list* dst, struct list* const src, list_iterator_t pos);
void list__merge_before(struct list* dst, struct list* const src, list_iterator_t pos);



/*
 * list getters and setters
*/

size_t list__size(struct list* const list);
int list__is_empty(struct list* const list);
void* list__get_at(struct list* const list, size_t index);
void* list__get_front(struct list* const list);
void* list__get_back(struct list* const list);
const void* list__get_at_const(struct list* const list, size_t index);
const void* list__get_front_const(struct list* const list);
const void* list__get_back_const(struct list* const list);
void** list__get_at_addr(struct list* const list, size_t index);
void** list__get_front_addr(struct list* const list);
void** list__get_back_addr(struct list* const list);
const void** list__get_at_addr_const(struct list* const list, size_t index);
const void** list__get_front_addr_const(struct list* const list);
const void** list__get_back_addr_const(struct list* const list);
void list__set_node_destructor(struct list* list, list_node_destructor_t node_destructor);
list_iterator_t list__begin(struct list* const list);
list_iterator_t list__end(struct list* const list);
list_reverse_iterator_t list__reverse_begin(struct list* const list);
list_reverse_iterator_t list__reverse_end(struct list* const list);
list_iterator_t __list__find_impl(struct list* const list, void* data, size_t type_size);
list_iterator_t list__find_if(struct list* const list, int(*predicate)(void* data));

#define list__find(ptr, data, data_type)    \
    __list__find_impl(ptr, data, sizeof(data_type))



/*
 * list iterator functions
*/

list_iterator_t list_iterator__next(list_iterator_t* iter);
list_iterator_t list_iterator__advance(list_iterator_t* iter, size_t n);
list_reverse_iterator_t list_reverse_iterator__next(list_reverse_iterator_t* iter);
list_reverse_iterator_t list_reverse_iterator__advance(list_reverse_iterator_t* iter, size_t n);
void* list_iterator__extract_data(list_iterator_t iter);
void** list_iterator__extract_data_addr(list_iterator_t iter);

#endif // __C_LINKED_LISTS__LIST_H
